package com.settlement.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.settlement.system.common.base.IBaseEnum;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.CancellationStatusEnum;
import com.settlement.system.common.enums.OMSOrderTypeEnum;
import com.settlement.system.common.enums.OrderEnum;
import com.settlement.system.common.model.Option;
import com.settlement.system.mapper.*;
import com.settlement.system.model.entity.*;
import com.settlement.system.model.query.FileAuditPageQuery;
import com.settlement.system.model.vo.AuditVo;
import com.settlement.system.model.vo.RoleVO;
import com.settlement.system.model.vo.SysBillVO;
import com.settlement.system.model.vo.SysOrderDetailVo;
import com.settlement.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 标准核销表 服务实现类
 * </p>
 *
 * @author huangrensen
 * @since 2023-08-05
 */
@Service
@RequiredArgsConstructor
public class SysFileAuditServiceImpl extends ServiceImpl<SysFileAuditMapper, SysFileAudit> implements SysFileAuditService {

    private final SysAuditRuleMapper auditRuleService;

    private final SysAuditService auditService;

    private final SysCompanyService sysCompanyService;

    private final SysDictService sysDictService;

    private final RedisTemplate redisTemplate;

    private final SysAuditNoLinkMapper auditNoLinkMapper;

    private final SysRoleService roleService;

    private final BsOmsOrderMapper bsOmsOrderMapper;

    private final SysBillMapper sysBillMapper;

    private final SysStoreService storeService;

    private final SysSubjectsService sysSubjectsService;

    private final SysPlatformService sysPlatformService;

    private final SysOrderDetailMapper orderDetailMapper;

    @Override
    public Page<SysFileAudit> getFileAuditPage(FileAuditPageQuery queryParams) {
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        // 拼接月份列表
        List<String> monthList = new ArrayList<>();
        String endMonthStr = queryParams.getEndMonth().replaceAll("-", "");
        LocalDate endMonth = LocalDate.parse(endMonthStr + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
        LocalDate startTime = LocalDate.parse(queryParams.getStartMonth().replaceAll("-", "") + "01", DateTimeFormatter.ofPattern(
                "yyyyMMdd"));
        // 获取已经生成的表名
        Object object = redisTemplate.opsForValue().get(SystemConstants.FILE_AUDIT_KEY);
        List<String> tableNameList;
        if(object != null){
            tableNameList = (List<String>) object;
        }else{
            tableNameList = this.baseMapper.getAllTable();
            // 添加缓存
            redisTemplate.opsForValue().set(SystemConstants.FILE_AUDIT_KEY, tableNameList, 1, TimeUnit.HOURS);
        }
        // 循环追加月份
        while (!startTime.isAfter(endMonth)) {
            monthList.add(startTime.format(DateTimeFormatter.ofPattern("yyyyMM")));
            startTime = startTime.plusMonths(1);
        }
        // 根据月份判断数据库表是否存在
        List<String> existTableList = new ArrayList<>();
        String tableName;
        for (String month : monthList) {
            tableName = "sys_file_audit_%s".formatted(month);
            if (tableNameList.contains(tableName)) {
                existTableList.add(tableName);
            }
        }
        if (existTableList.size() == 0) {
            return new Page<>(pageNum, pageSize);
        }
        queryParams.setTableNameList(existTableList);
        Page<SysFileAudit> page = new Page<>(pageNum, pageSize);
        Page<SysFileAudit> auditPage = this.baseMapper.getPage(page, queryParams);
        // 是否核销
        List<Option> options = sysDictService.listDictOptions("hasAudit");
        for (SysFileAudit record : auditPage.getRecords()) {
            options.stream().filter(option -> option.getValue().equals(record.getAudit()))
                    .findFirst()
                    .ifPresent(option -> record.setAudit(option.getLabel()));
        }
        // 核销结果分类
        options = sysDictService.listDictOptions("jgfl");
        for (SysFileAudit record : auditPage.getRecords()) {
            options.stream().filter(option -> option.getValue().equals(record.getMainTypeName()))
                    .findFirst()
                    .ifPresent(option -> record.setMainTypeName(option.getLabel()));
        }
        List<SysCompany> sysCompanyList = sysCompanyService.list();
        for (SysFileAudit record : auditPage.getRecords()) {
            sysCompanyList.stream().filter(sysCompany -> sysCompany.getCode().equals(record.getReceiveCompany()))
                    .findFirst()
                    .ifPresent(sysCompany -> record.setReceiveCompany(sysCompany.getName()));
        }
        return auditPage;
    }

    @Override
    public boolean existTable(String tableName) {
        String result = this.getBaseMapper().existTable(tableName);
        return result != null;
    }

    @Override
    public boolean createTable(String tableName) {
        return this.getBaseMapper().createTable(tableName) > 0;
    }

    @Override
    public int insertData(SysFileAudit fileAudit) {
        return this.getBaseMapper().insertData(fileAudit);
    }

    @Override
    public AuditVo getAuditForm(String auditId, String billMonth) {
        AuditVo auditVo = new AuditVo();
        SysFileAudit queryParams = new SysFileAudit();
        queryParams.setTableName("sys_file_audit_%s".formatted(billMonth));
        queryParams.setId(auditId);
        List<SysFileAudit> sysAudits = this.baseMapper.getById(queryParams);
        List<RoleVO> roleList = roleService.listAll();
        if (sysAudits.size() > 0) {
            SysFileAudit sysAudit = sysAudits.get(0);
            BeanUtil.copyProperties(sysAudit, auditVo);
            if (StringUtils.hasText(sysAudit.getReceiveCompany())) {
                SysCompany company = sysCompanyService.getCompanyByCode(sysAudit.getReceiveCompany());
                if (company != null) {
                    auditVo.setReceiveCompanyName(company.getName());
                }
            }
            if (CancellationStatusEnum.NO.getValue().equals(sysAudit.getAuditStatus())) {
                auditVo.setAuditStatus(CancellationStatusEnum.NO.getLabel());
            } else {
                auditVo.setAuditStatus(CancellationStatusEnum.YES.getLabel());
            }
            List<Option> options = sysDictService.listDictOptions("jgfl");
            for (Option option : options) {
                if (option.getValue().equals(sysAudit.getMainTypeName())) {
                    auditVo.setMainTypeName(option.getLabel());
                    break;
                }
            }
            // 核销状态
            roleList.stream().filter(option -> option.getCode().equals(sysAudit.getBelongRole()))
                    .findFirst()
                    .ifPresent(option -> auditVo.setAuditStatus("待%s处理".formatted(option.getName())));
        }
        return auditVo;
    }

    @Override
    public void antiAudit(String auditId, String billMonth) {
        SysFileAudit queryParams = new SysFileAudit();
        queryParams.setTableName("sys_file_audit_%s".formatted(billMonth));
        queryParams.setId(auditId);
        List<SysFileAudit> sysAudits = this.baseMapper.getById(queryParams);
        Assert.isTrue(sysAudits.stream().noneMatch(sysFileAudit -> BigDecimal.ZERO.equals(sysFileAudit.getReconciliationAmount())), "所选的归档核销单【财务调账金额】已为零，不允许反审核");
        for (SysFileAudit sysAudit : sysAudits) {
            // 反审核后，系统自动将财务调账金额清零（应收账款余额重算后≠0），核销单变为初始状态，重新进入核销轮巡（36条）
            sysAudit.setReconciliationAmount(BigDecimal.ZERO);
            // 查出36条核销规则，按照优先级排序
            List<SysAuditRule> ruleList = auditRuleService.selectList(null);
            ruleList.sort(Comparator.comparing(SysAuditRule::getPriority));
            SysAudit audit = new SysAudit();
            BeanUtil.copyProperties(sysAudit, audit, "id");
            audit.sumReceiveBillAmount();
            audit.setBillDate(billMonth);
            auditService.rulerCheck(ruleList, audit);
        }
    }

    @Override
    public List<SysOrderDetailVo> getOrderDetailList(String fileAuditId, String linkNo) {
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysAuditNoLink> allAuditNoLinks = new ArrayList<>();
        List<SysAuditNoLink> sysAuditNoLinks;
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(linkNo);
            query.setType(OrderEnum.ORDER.getValue());
            sysAuditNoLinks = auditNoLinkMapper.getList(query);
            if (sysAuditNoLinks.size() > 0) {
                allAuditNoLinks.addAll(sysAuditNoLinks);
            }
        }
        List<SysOrderDetail> orderDetailList = new ArrayList<>();
        List<SysOrderDetailVo> orderDetailVoList = new ArrayList<>();
        // 先查出关联的ID，通过ID前面6位数字可以知道是属于那个月份的表
        if (allAuditNoLinks.size() == 0) {
            return orderDetailVoList;
        }
        List<String> billMonthList = new ArrayList<>();
        String billMonth;
        for (SysAuditNoLink sysAuditNoLink : allAuditNoLinks) {
            billMonth = sysAuditNoLink.getTableId().substring(0, 6);
            if(billMonthList.contains(billMonth)){
                continue;
            }
            billMonthList.add(billMonth);
        }
        // 根据订单ID查询订单详情
        SysOrderDetail sysOrderDetail;
        List<SysOrderDetail> sysOrderDetails;
        for (String bMonth : billMonthList) {
            sysOrderDetail = new SysOrderDetail();
            sysOrderDetail.setFileAuditId(fileAuditId);
            sysOrderDetail.setTableName("sys_order_detail_%s".formatted(bMonth));
            sysOrderDetails = orderDetailMapper.getList(sysOrderDetail);
            if(sysOrderDetails.size() > 0){
                orderDetailList.addAll(sysOrderDetails);
            }
        }
        List<String> idList = orderDetailList.stream().map(SysOrderDetail::getLinkId).distinct().toList();
        List<BsOmsOrderDetail> allDetailList = new ArrayList<>();
        BsOmsOrderDetail detailQuery;
        for (String bMonth : billMonthList) {
            detailQuery = new BsOmsOrderDetail();
            detailQuery.setTableName("bs_oms_order_detail_%s".formatted(bMonth));
            detailQuery.setOIdList(idList);
            List<BsOmsOrderDetail> list = bsOmsOrderMapper.getDetailList(detailQuery);
            if(list.size() > 0){
                allDetailList.addAll(list);
            }
        }
        SysStore sysStore;
        BsOmsOrderDetail vo;
        SysOrderDetailVo detailVo;
        for (SysOrderDetail orderDetail : orderDetailList) {
            // 填充店铺
            sysStore = storeService.getById(orderDetail.getStoreId());
            if (Objects.nonNull(sysStore)) {
                orderDetail.setStoreName(sysStore.getCommercePlatformStoreName());
            }
            if (Objects.nonNull(orderDetail.getOrderType())) {
                orderDetail.setOrderTypeName(IBaseEnum.getLabelByValue(orderDetail.getOrderType(), OMSOrderTypeEnum.class));
            }
            detailVo = new SysOrderDetailVo();
            BeanUtils.copyProperties(orderDetail, detailVo);
            vo = allDetailList.stream().filter(detail -> Objects.equals(detail.getOId(), orderDetail.getLinkId())).findFirst().orElse(null);
            if (Objects.nonNull(vo)) {
                BeanUtils.copyProperties(vo, detailVo, "id");
            }
            orderDetailVoList.add(detailVo);
        }
        return orderDetailVoList;
    }

    @Override
    public List<SysBillVO> getBillDetail(String fileAuditId, String linkNo) {
        List<SysBillVO> allBillVOS = new ArrayList<>();
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysAuditNoLink> allAuditNoLinks = new ArrayList<>();
        List<SysAuditNoLink> sysAuditNoLinks;
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(linkNo);
            query.setType(OrderEnum.BILL.getValue());
            sysAuditNoLinks = auditNoLinkMapper.getList(query);
            if (sysAuditNoLinks.size() > 0) {
                allAuditNoLinks.addAll(sysAuditNoLinks);
            }
        }
        if (allAuditNoLinks.size() == 0) {
            return allBillVOS;
        }
        List<SysPlatform> platformList = sysPlatformService.list();
        List<SysCompany> sysCompanyList = sysCompanyService.list();
        // 账单月份
        String tableName;
        List<SysBill> sysBillList;
        List<SysBill> sysOrderList = new ArrayList<>();
        String[] billMonthArray;
        for (SysAuditNoLink sysAuditNoLink : allAuditNoLinks) {
            billMonthArray = sysAuditNoLink.getTableId().split(",");
            for (String billMonth : billMonthArray) {
                if(!com.settlement.system.common.util.StringUtils.hasText(billMonth)){
                    continue;
                }
                if(billMonth.length() > 6){
                    // 旧数据兼容处理
                    tableName = "sys_bill_%s".formatted(billMonth.substring(0, 6));
                }else{
                    tableName = "sys_bill_%s".formatted(billMonth);
                }
                sysBillList = sysBillMapper.getBillByLinkNo(tableName, sysAuditNoLink.getLinkNo());
                if (sysBillList.size() > 0) {
                    for (SysBill sysBill : sysBillList) {
                        if(Objects.equals(fileAuditId, sysBill.getFileAuditId())){
                            sysOrderList.add(sysBill);
                        }
                    }
                }
            }
        }
        SysBillVO vo;
        List<String> codes = new ArrayList<>();
        for (SysBill record : sysOrderList) {
            if (!codes.contains(record.getLastCode())) {
                codes.add(record.getLastCode());
            }
            if (!codes.contains(record.getOtherLastCode())) {
                codes.add(record.getOtherLastCode());
            }
            vo = new SysBillVO();
            BeanUtil.copyProperties(record, vo, "accessory", "otherAccessory");
            if (Objects.isNull(vo.getBillAmount())) {
                vo.setBillAmount(BigDecimal.ZERO);
            }
            if (org.springframework.util.StringUtils.hasText(record.getAccessory())) {
                vo.setAccessory(JSONObject.parseObject(record.getAccessory(), Map.class));
            }
            if (org.springframework.util.StringUtils.hasText(record.getOtherAccessory())) {
                vo.setOtherAccessory(JSONObject.parseObject(record.getOtherAccessory(), Map.class));
            }
            allBillVOS.add(vo);
        }
        List<SysSubjects> sysSubjectsList;
        if (codes.size() == 0) {
            sysSubjectsList = new ArrayList<>();
        } else {
            sysSubjectsList = sysSubjectsService.list(new LambdaQueryWrapper<SysSubjects>().in(SysSubjects::getLastCode, codes));
        }
        for (SysBillVO recordVo : allBillVOS) {
            sysSubjectsList.stream().filter(sysSubjects -> sysSubjects.getLastCode().equals(recordVo.getLastCode()))
                    .findFirst()
                    .ifPresent(sysSubjects -> {
                        recordVo.setLastName(sysSubjects.getLastName());
                        recordVo.setFirstCode(sysSubjects.getFirstCode());
                        recordVo.setFirstName(sysSubjects.getFirstName());
                        recordVo.setBorrowing(sysSubjects.getBorrowing());
                    });
            sysSubjectsList.stream().filter(sysSubjects -> sysSubjects.getLastCode().equals(recordVo.getOtherLastCode()))
                    .findFirst()
                    .ifPresent(sysSubjects -> {
                        recordVo.setOtherLastName(sysSubjects.getLastName());
                        recordVo.setOtherFirstCode(sysSubjects.getFirstCode());
                        recordVo.setOtherFirstName(sysSubjects.getFirstName());
                        recordVo.setOtherBorrowing(sysSubjects.getBorrowing());
                    });
            // 对方账单金额
            recordVo.setOtherBillAmount(recordVo.getBillAmount());
            // 对账系统平台名称
            platformList.stream().filter(platform -> platform.getReconciliationSystemCode().equals(recordVo.getBillSystemPlatformCode()))
                    .findFirst()
                    .ifPresent(platform -> {
                        recordVo.setBillSystemPlatformName(platform.getReconciliationSystemName());
                    });
            // 入账主体
            sysCompanyList.stream().filter(sysCompany -> sysCompany.getCode().equals(recordVo.getCompanyCode()))
                    .findFirst()
                    .ifPresent(sysCompany -> recordVo.setCompanyCode(sysCompany.getName()));
        }
        // 金额从大到小排序
        allBillVOS.sort((o1, o2) -> o2.getBillAmount().compareTo(o1.getBillAmount()));
        return allBillVOS;
    }
}
